package framework
{
    import flash.events.Event;
    import flash.events.IEventDispatcher;
    import flash.utils.Proxy;
    import flash.utils.flash_proxy;

    [Event(name="propertyChange",type="mx.events.PropertyChangeEvent")]
    [Bindable(event="propertyChange")]
    dynamic public class Ctx extends Proxy implements IEventDispatcher, ICtx
    {
        /**
         *
         * @default
         */
        public static var contexts:Object = {};

        /**
         *
         * @param contextName
         */
        public function Ctx(contextName:String = "default")
        {
            this.contextName = contextName;
        }

        /**
         *
         * @default
         */
        public var contextName:String;

        private var nextNameArray:Array;

        /**
         *
         * @param type
         * @param listener
         * @param useCapture
         * @param priority
         * @param useWeakReference
         */
        public function addEventListener(type:String, listener:Function, useCapture:Boolean = false, priority:int = 0, useWeakReference:Boolean = false):void
        {
            ctx.addEventListener(type, listener, useCapture, priority, useWeakReference);
        }

        /**
         *
         * @return
         */
        public function get ctx():CtxCore
        {
            var ctx:CtxCore = contexts[contextName];
            if (!ctx)
            {
                ctx = new CtxCore;
                contexts[contextName] = ctx;
                ctx.registerInstance(ctx, "c");
                registerBeans();
            }
            return ctx;
        }

        /**
         *
         * @param id
         * @return
         */
        public function deleteBean(id:String):Boolean
        {
            return ctx.deleteBean(id);
        }

        /**
         *
         * @param event
         * @return
         */
        public function dispatchEvent(event:Event):Boolean
        {
            return ctx.dispatchEvent(event);
        }

        /**
         *
         * @param id
         * @return
         */
        public function getBean(id:String):*
        {
            return ctx.getBean(id);
        }

        /**
         *
         * @param bean
         * @return
         */
        public function getBeanId(bean:*):String
        {
            return ctx.getBeanId(bean);
        }

        /**
         *
         * @param clazz
         * @return
         */
        public function getBeansByType(clazz:Class):Array
        {
            return ctx.getBeansByType(clazz);
        }

        /**
         *
         * @param id
         * @return
         */
        public function hasBean(id:String):Boolean
        {
            return ctx.hasBean(id);
        }

        /**
         *
         * @param type
         * @return
         */
        public function hasEventListener(type:String):Boolean
        {
            return ctx.hasEventListener(type);
        }


        public function register(clazzOrInstance:Object, id:String = null):*
        {
            return ctx.register(clazzOrInstance, id);
        }


        public function registerInstance(instance:*, id:String = null):*
        {
            return ctx.registerInstance(instance, id);
        }


        public function registerClass(clazz:Class, id:String = null):*
        {
            return ctx.registerClass(clazz, id);
        }

        /**
         *
         * @param type
         * @param listener
         * @param useCapture
         */
        public function removeEventListener(type:String, listener:Function, useCapture:Boolean = false):void
        {
            ctx.removeEventListener(type, listener, useCapture);
        }

        /**
         *
         * @param type
         * @return
         */
        public function willTrigger(type:String):Boolean
        {
            return ctx.willTrigger(type);
        }

        /**
         *
         */
        protected function registerBeans():void
        {

        }

        flash_proxy override function callProperty(name:*, ... rest):*
        {
            return getBean(name).apply(this, rest)
        }

        flash_proxy override function deleteProperty(name:*):Boolean
        {
            return deleteBean(name);
        }

        flash_proxy override function getProperty(name:*):*
        {
            return getBean(name);
        }

        flash_proxy override function hasProperty(name:*):Boolean
        {
            return hasBean(name);
        }

        /**
         *  @private
         */
        flash_proxy override function nextName(index:int):String
        {
            return nextNameArray[index - 1];
        }

        /**
         *  @private
         */
        flash_proxy override function nextNameIndex(index:int):int
        {
            if (index == 0)
            {
                nextNameArray = [];
                for (var op:String in ctx.beans)
                {
                    nextNameArray.push(op);
                }
            }
            return index < nextNameArray.length ? index + 1 : 0;
        }

        flash_proxy override function nextValue(index:int):*
        {
            return ctx.beans[nextNameArray[index - 1]];
        }

        flash_proxy override function setProperty(name:*, value:*):void
        {
            registerInstance(name, value);
        }
    }
}
